package server

import (
	"common/biz"
	"common/database"
	"common/logs"
	"context"
	"core/dao"
	"core/models/entity"
	"core/models/request"
	"core/repo"
	"encoding/json"
	"errors"
	"fmt"
	"framework/msError"
	"io/ioutil"
	"net/http"
	"strconv"
	"time"
	"user/pb"
)

type AccountServer struct {
	pb.UnimplementedUserServiceServer
	redisDao   dao.RedisDao
	accountDao dao.AccountDao
	Manager    *repo.Manager
}

func NewAccountServer(manager *repo.Manager) *AccountServer {
	manager.Mysql = database.NewMysql()
	return &AccountServer{
		Manager:    manager,
		redisDao:   *dao.NewRedisDao(manager),
		accountDao: *dao.NewAccountDao(manager),
	}
}

func (a *AccountServer) WxAutoLogin(ctx context.Context, req *pb.WxAutologinParams) (*pb.WxAutologinResponse, error) {
	resp, err := a.wxautoLogin(ctx, req)
	if err != nil {
		return nil, msError.GrpcError(msError.NewError(1, err))
	}
	return resp, nil

}
func (a *AccountServer) wxautoLogin(ctx context.Context, req *pb.WxAutologinParams) (*pb.WxAutologinResponse, error) {
	session, err := a.getSessionInfo(req.Code, req.Gid)
	if err != nil {
		logs.Error("wx login ,getsessionInfo err:%v", err)

		return nil, err
	}
	// mysql查询是否存在用户，不存在就写入一条
	var user entity.User
	_ = a.Manager.Mysql.GOrm.Where("wx_openid=?", session.OpenID).Find(&user).Error

	user.LastLoginIp = req.Ip
	nowTime := time.Now().Unix()
	user.LastLoginTime = nowTime
	nowDate, _ := strconv.ParseInt(time.Now().Format("20060102"), 10, 64)
	if len(user.WxOpenid) == 0 {
		user.Gid = int64(req.Gid)
		user.WxOpenid = session.OpenID
		user.RegDate = nowDate
		user.RegTIme = nowTime
		a.Manager.Mysql.GOrm.Create(&user)
		// 用户归因
		go a.AddUserAttr(ctx, &user, req)
	} else {
		a.Manager.Mysql.GOrm.Save(&user)
	}
	// 写入一条归因记录
	go a.addClickLog(ctx, &user, req)
	// redis存储一下sessionkey
	f := fmt.Sprintf("%d_%d", user.Gid, user.ID)
	d, _ := json.Marshal(session)
	a.Manager.Redis.HSet(ctx, "wx_user_info", f, string(d))
	// 写一条日志登录日志 到mangodb
	log := &entity.LoginLog{
		Uid:          user.ID,
		EventDate:    nowDate,
		EventTime:    nowTime,
		WxOpenid:     user.WxOpenid,
		RegTIme:      user.RegTIme,
		RegDate:      user.RegDate,
		Gid:          user.Gid,
		Ip:           user.LastLoginIp,
		Account:      user.Account,
		WxSessionKey: session.SessionKey,
	}
	err = a.accountDao.SaveLoginLog(ctx, log)
	if err != nil {
		logs.Error("SaveLoginLog err:%v", err)
		return nil, err
	}
	resp := &pb.WxAutologinResponse{}
	resp.Gid = int32(user.Gid)
	resp.Openid = user.WxOpenid
	resp.SessionKey = session.SessionKey
	resp.Uid = fmt.Sprintf("%d", (user.ID))

	return resp, nil
}

func (a *AccountServer) AddUserAttr(ctx context.Context, user *entity.User, req *pb.WxAutologinParams) {
	var extMap map[string]interface{}
	data := []byte(req.Ext)
	err := json.Unmarshal(data, &extMap)
	if err != nil {
		logs.Error("wx ext parse err,%s", err.Error())
	}

	query, ok := extMap["query"].(map[string]interface{})
	if !ok {
		return
	}
	source, ok := query["source"].(string)
	if !ok {
		return
	}
	scene, ok := extMap["scene"].(float64)
	if !ok {
		scene = 0
	}
	// 判断用户是否有归因记录
	nowTime := time.Now().Unix()
	ymd, _ := strconv.ParseInt((time.Now().Format("20060102")), 10, 64)
	clickLog := &entity.UserCLickAttr{
		Gid:    int64(req.Gid),
		Uid:    user.ID,
		Ymd:    ymd,
		Key:    "wx_shource",
		Scene:  int16(scene),
		Value:  source,
		Ext:    req.Ext,
		Ext1:   "",
		OpenID: user.WxOpenid,
		ATime:  nowTime,
	}
	_ = a.accountDao.AddUserAttr(ctx, clickLog)
}

func (a *AccountServer) addClickLog(ctx context.Context, user *entity.User, req *pb.WxAutologinParams) {
	nowTime := time.Now().Unix()
	var extMap map[string]interface{}
	data := []byte(req.Ext)
	_ = json.Unmarshal(data, &extMap)

	scene, ok := extMap["scene"].(float64)
	if !ok {
		scene = 0
	}
	ymd, _ := strconv.ParseInt((time.Now().Format("20060102")), 10, 64)
	clickLog := &entity.ClickLog{
		Gid:    int64(req.Gid),
		Uid:    user.ID,
		OpenId: user.WxOpenid,
		Scene:  int16(scene),
		Ip:     req.Ip,
		Ymd:    ymd,
		ATime:  nowTime,
		Param:  req.Ext,
	}
	a.accountDao.AddClickLog(ctx, clickLog)
}

func (a *AccountServer) Register(ctx context.Context, req *pb.RegisterParams) (*pb.RegisterResponse, error) {
	var uid string
	if req.LoginPlatform == request.WeiXin {
		acc, err := a.wxRegister(req)
		if err != nil {
			return &pb.RegisterResponse{
				Uid: uid,
			}, err
		}
		uid = acc.Uid
	}
	return &pb.RegisterResponse{
		Uid: uid,
	}, nil
}

func (a *AccountServer) wxRegister(req *pb.RegisterParams) (*entity.Account, error) {
	ac := &entity.Account{
		WxAccount:  req.Account,
		CreateTime: time.Now(),
	}
	// 2. 需要生成几个数字作为用户唯一id，redis自增
	uid, err := a.redisDao.NextAccountId()
	if err != nil {
		return ac, biz.SqlError
	}
	ac.Uid = uid
	err = a.accountDao.SaveAccount(context.TODO(), ac)
	if err != nil {
		return ac, biz.SqlError
	}
	return ac, nil
}

// 获取用户基本信息
func (a *AccountServer) getSessionInfo(code string, gid int32) (*entity.SessionInfo, error) {
	var (
		AppID     = ""
		AppSecret = ""
	)
	var game entity.GameM
	var err error
	err = a.Manager.Mysql.GOrm.Where("ID = ?", gid).First(&game).Error

	if err != nil || len(game.Appid) == 0 {
		logs.Error("get wxingo err:%v", err)
		return nil, err
	}
	AppID = game.Appid
	AppSecret = game.Secret

	// 通过gid获取配置
	loginURL := fmt.Sprintf("https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code",
		AppID, AppSecret, code)
	logs.Info("loginURL:%s", loginURL)
	resp, err := http.Get(loginURL)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	var session entity.SessionInfo
	logs.Info(string(body))
	err = json.Unmarshal(body, &session)
	if err != nil {
		return nil, err
	}
	if len(session.OpenID) == 0 {
		return nil, errors.New("获取openid失败")
	}

	return &session, nil
}

// 获取用户头像、位置、session_key、openid
// func (a *AccountServer) getUserinfo(accessToken, openid string) {
// 	loginURL := fmt.Sprintf("https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s&lang=zh_CN",
// 		accessToken, openid)
// 	resp, err := http.Get(loginURL)
// 	if err != nil {
// 		return nil, err
// 	}
// 	defer resp.Body.Close()

// 	body, err := ioutil.ReadAll(resp.Body)
// 	if err != nil {
// 		return nil, err
// 	}

// 	var session entity.SessionInfo
// 	err = json.Unmarshal(body, &session)
// 	if err != nil {
// 		return nil, err
// 	}

// 	return nil
// }

// getAccessToken 从微信服务器获取access_token
func getAccessToken(appID, appSecret string) (*entity.AccessToken, error) {
	// 构建请求URL
	url := fmt.Sprintf("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s", appID, appSecret)

	// 发送HTTP GET请求
	resp, err := http.Get(url)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	// 读取响应体
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	// 解析JSON响应
	var token entity.AccessToken
	err = json.Unmarshal(body, &token)
	if err != nil {
		return nil, err
	}

	// 检查是否有错误码
	if token.ErrCode != 0 {
		return nil, fmt.Errorf("获取access_token失败，错误码: %d, 错误信息: %s", token.ErrCode, token.ErrMsg)
	}

	return &token, nil
}
